Skip to content

feat: Fable weekly bar, separate accounts for two organizations of one login, session bar only when reported - #1

Open
dragosdobro wants to merge 3 commits into
2solarmax:mainfrom
dragosdobro:feat/fable-bar-and-org-accounts
Open

dragosdobro wants to merge 3 commits into
2solarmax:mainfrom
dragosdobro:feat/fable-bar-and-org-accounts

Conversation

@dragosdobro

@dragosdobro dragosdobro commented Oct 27, 2026 •

Copy link
Copy Markdown

Three changes on one branch, one commit each, on top of v1.24.93.

1. Fable weekly bar in the TUI (feat(tui))

  • Each account row shows Ses | Fbl | Wk: the Fable weekly usage and its time to reset sit between the session and week bars.
  • The bar shows a dash when there is no Fable reading or the Fable limit is inactive.
  • It appears from 112 columns; narrower terminals look as before. Bar widths are computed from the column layout (including the Where column), so a row is never longer than today's widest row.

2. Two organizations of one Claude login as separate accounts (feat(accounts))

One Claude login can belong to several organizations, for example a Team org and a personal Max org under the same email. Today every dedupe site compares accountUuid only, so logging in to the second organization re-authenticates the first account instead of adding a new one.

  • An OAuth account is identified by user uuid + organization uuid. fetchProfile returns organization.uuid, stored as organizationUuid.
  • Every dedupe site (TUI login, maxpool login, token persistence, sync from disk, config writer, maxpool accounts, state.json restore) uses one shared predicate in src/oauth.js; a source guard test keeps raw accountUuid comparisons out of src/.
  • Accounts saved before this change learn their organization read-only from their own unexpired access token (never a refresh). If that is not possible, the TUI asks Re-authenticate it (r) or add a second account (a)? [r]; maxpool login re-authenticates in place and prints a --name hint.
  • When the email is already an account name, the suggested name for the second account is <email> (<plan type>).
  • maxpool accounts no longer renames two accounts to the same email.
  • Team pool: the login routing (_routeLogin, maxpool login's local-or-cloud choice), the remote login sender (cloud-login.js), the POST /maxpool/accounts inject and duplicate detection compare the organization too, and /maxpool/status exports organizationUuid.

3. Leave out the session bar when no account reports one (feat(tui))

Verified Ultra accounts no longer report a 5-hour window (upstream already treats a missing 5h reading as no limit, cff65b2). When no account in the pool reports a session reading, the Ses column is dropped: Wk always shows and Fbl joins it from 97 columns. As soon as any Claude, API-key or provider account reports one, every row shows Ses again.

Testing

  • New tests: test/tui-fable-bar.test.js (11), test/account-identity.test.js (11), test/same-email-accounts.test.js (14), test/tui-session-collapse.test.js (4), plus organization cases in test/remote-inject.test.js, test/tui-remote-login.test.js and test/pool-link.test.js.
  • Before the rebase: npm test with an isolated HOME on Node 18.20.8, 20.20.2, 22.23.3, 24.19.0 and 26.8.2, compared with untouched main on each version: no new failures.
  • After the rebase on v1.24.93 (Node 26.8.2, isolated HOME, every test file except test/rc-gate.test.js, which hung on this machine on both trees, all files at once): 2014 tests, 4 failures. Three also fail on untouched v1.24.93 in the same run (the two below and tui-terminal-pty "(c) self-update hand-off"). The fourth, tui-terminal-pty "(e) a crash that does not exit", passes alone 3/3 on both this branch and untouched v1.24.93 (load-sensitive pty timing). Untouched v1.24.93: 1970 tests, 4 failures (one only because that copy had no git metadata).
  • Failures that also occur on untouched main on this macOS machine:
    • release-stage-watchdog "a FROZEN stage is killed at its ceiling": needs a timeout binary that macOS does not ship (all versions).
    • family-fallback "the default really is 250ms": Node 26 only.
  • Lint: clean.
  • Manual check: a separate instance with an empty config on another port; one login through maxpool login, a second login to the other organization of the same user through the TUI. Result: two accounts, one user uuid, two organization uuids (claude_max, claude_team).

Notes

  • With an empty accounts list, maxpool server exits with "No accounts configured" and the supervisor restarts it in a loop that ignores Ctrl+C. Not changed here; on a fresh install the first login has to be maxpool login.
  • The profile request made during login has no timeout, as before.
  • No version bump, no CHANGELOG edit.

@dragosdobro dragosdobro changed the title feat: Fable weekly bar in the TUI; keep two organizations of one login as separate accounts Feature: Add a Fable TUI usage bar and allow multiple organizations belonging to the same login as separate accounts Oct 27, 2026
@dragosdobro
dragosdobro force-pushed the feat/fable-bar-and-org-accounts branch from d13bfeb to 284e869 Compare November 5, 2026 11:11
@dragosdobro dragosdobro changed the title Feature: Add a Fable TUI usage bar and allow multiple organizations belonging to the same login as separate accounts feat: Fable weekly bar, separate accounts for two organizations of one login, session bar only when reported Nov 5, 2026
@dragosdobro
dragosdobro force-pushed the feat/fable-bar-and-org-accounts branch from 9f78a89 to 7a953d9 Compare November 12, 2026 12:37
2solarmax added a commit that referenced this pull request Nov 13, 2026
…hold, direct reactive gate, cap-measured room, distinct identities

#1 a GENERAL hold counts a peer only if every ACTIVE model bucket it reports also
   has >=35% room (a Fable-exhausted peer would leave Fable with no route).
#2 a hold notes its reason and falls through: the model loop still claims a dying
   model grant, and a model wall with no room elsewhere.
#3 the reactive 429 path evaluates the hold directly (wallClaimHeld: header-fresh
   refill stamp, grant end, live peer count) instead of matching the sweep's
   reason string — a stale probe/listing at the wall no longer falls through to a
   claim. Scoped 429s get the same per-model gate. Comment corrected.
#4 peer room is measured to its effective caps on both windows (weekly cap, else
   1.0; 5h bench = min(5h cap, 0.90)).
#6 peers sharing one capacityIdentity count once.
wallClaimHeld is the one hold rule shared by the sweep and the reactive path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TMppTxPFhguyMkcjkNvdb9
2solarmax added a commit that referenced this pull request Nov 13, 2026
…-wide budget, #4 identity-less peer); #3 driven in server order

At 5865365: 6 of 40 fail (RT2-1 x2, RT2-2 x3, RT2-4). The #3 server-order
tests pass at 5865365 by design: they replace a seeded state production never
produces with markRateLimited -> tryReactiveClaim, pinning that a Fable 429
never spends on the fast path and that no 429 retry-after stands in for the
refill. Pool fixture accounts now carry a resolvable identity.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TMppTxPFhguyMkcjkNvdb9
2solarmax added a commit that referenced this pull request Nov 13, 2026
…d budget, identity-less peers skipped

#1 a wall either path HELD is registered (account._wallHold) and live only while
   no claim superseded it and the account is still at that wall with the refill
   ahead (isHoldingWall). Every sweep whose own probe fails (timeout/error/throw)
   or whose listing is stale re-runs wallClaimHeld through the reactive route
   (stored listing <=6h, peers' live freshness): capacity unknown -> claim. A
   listing cooldown still blocks; a never-held wall keeps today's behaviour.
#2 a hold needs holdMinPeers x (walls holding in this pool, this one included)
   roomy peers — 4 walls on 2 peers: one holds, three claim. Same on the 429 path.
#3 the fast path's Fable branch is unreachable from a 429 (markRateLimited marks
   the bucket reactive first, and the pick refuses reactive buckets); it is
   reached by the rescue of a sweep-held Fable wall, whose bucket is probe-
   measured — so its refill is a real reset stamp, never a retry-after. Tests
   now drive server order.
#4 a peer whose capacityIdentity is null is not counted; self is excluded by the
   same identity check.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TMppTxPFhguyMkcjkNvdb9
2solarmax added a commit that referenced this pull request Nov 13, 2026
Fail at 9a91a2a:
- R4-1 (#1 blocker): under the general hold, a Fable WALL grant dying before / within
  a day after the general refill is still claimed; one outliving it is skipped
- R4-2 (#2 major): a Fable claim under the hold, then a dark probe and no peer room
  -> the general reset is claimed (rescue and weekly 429)
- R4-3 (#3): spending a grant that clears the general weekly retires the hold,
  whatever the 429 kind or claim scope (sweep and fast path)
- R4-4 (#4): the hold records the refill it waits for; a later window is a new wall
- R3-4 updated (#5): every profile self serves needs its own roomy peers
- R4-6 (#6): the hold lets go before the stored listing ages past the 6h claim bound

Controls passing at both (by design): R4-2 control (one claim per general wall
still holds); R3-2 now runs its "no Fable reading" case through the real
countPeersWithRoom instead of a lambda that always answered 2 (#7).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TMppTxPFhguyMkcjkNvdb9
- New Fbl bar shows Fable weekly usage and time to reset; a dash when there is no data
- Appears on terminals 112 columns or wider; narrower screens look as before
- Bar widths are now computed from the column layout, so rows no longer overflow
- Tests cover the new bar and the width rules
…e accounts

- Accounts are told apart by user and organization, so a Team org and a personal org on the same email no longer overwrite each other
- Logging in to the other organization adds a second account; the same organization still re-authenticates in place
- Older accounts look up their organization with their own token; if that fails, the TUI asks whether to re-authenticate or add
- The second account's suggested name is `<email> (<plan>)`
- Team pool links, remote logins and duplicate detection compare the organization too
- Tests cover the matching on every login, save and restore path
…n window

- Plans without a 5-hour limit send no session reading; when no account has one, the Ses column is dropped
- Fbl and Wk take its room: Wk always shows, and Fbl joins it from 97 columns
- As soon as any Claude, API-key or provider account reports a session reading, every row shows Ses again
- Tests cover the layout and both cases
@dragosdobro
dragosdobro force-pushed the feat/fable-bar-and-org-accounts branch from 7a953d9 to d16bb57 Compare November 14, 2026 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant